#include <iostream>
#include <sstream>

#include <typeinfo>


#include <cppunit/TestCase.h>
#include <cppunit/TestFixture.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestSuite.h>

#include <cppunit/ui/text/TestRunner.h>

#include "PlantainParser.hpp"
#include "PlantainLexer.hpp"
#include "PlantainParserTokenTypes.hpp"

using namespace std;

class SimpleParserTest : public CppUnit::TestFixture{
public:
  void setUp(){
    ss = new stringstream(stringstream::in | stringstream::out);
    pl = new PlantainLexer(*ss);
    pp = new PlantainParser(*pl);
	pp->initializeASTFactory(ast_factory);
    pp->setASTFactory(&ast_factory);
  }
  void tearDown(){
    delete ss;
    delete pl;
    delete pp;
  }
protected:
  stringstream *ss;
  PlantainLexer *pl;
  PlantainParser *pp;
  antlr::ASTFactory ast_factory;

  void testDummy(){}

  void testSimple(){

    *ss << "123; 234.45";

    antlr::RefAST ast = antlr::nullAST;
    
    pp->program();
    ast = pp->getAST();

    if(ast == antlr::nullAST){
      CPPUNIT_FAIL("the returned AST is nullAST");
    }
    //printf("AST type %d with %d children: %s\n", (int)ast->getType(), ast->getNumberOfChildren(), ast->getText().c_str());
    CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)ast->getType());
    ast = ast->getNextSibling();
    //printf("AST type %d with %d children: %s\n", (int)ast->getType(), ast->getNumberOfChildren(), ast->getText().c_str());
    CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::FLOAT, (int)ast->getType());
  }

  void testLookup(){
    try{
      *ss << "foo.bar ";
      
      antlr::RefAST ast = antlr::nullAST;

      pp->program();

      ast = pp->getAST();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::DOT, (int)ast->getType());
      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      
    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testLookup2(){
    try{
      *ss << "foo.bar.baz ";
      
      antlr::RefAST ast = antlr::nullAST;

      pp->program();

      ast = pp->getAST();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::DOT, (int)ast->getType());
      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::DOT, (int)child->getType());

      antlr::RefAST grand = child->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)grand->getType());
      grand = grand->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)grand->getType());      

      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      
    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testProduct(){
    try{
      *ss << "foo*bar/10 ";
      
      antlr::RefAST ast = antlr::nullAST;

      pp->program();

      ast = pp->getAST();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::DIV, (int)ast->getType());
      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::STAR, (int)child->getType());

      antlr::RefAST grand = child->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)grand->getType());
      grand = grand->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)grand->getType());      

      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)child->getType());
      
    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testProduct2(){
    try{
      *ss << "foo%bar*10 ";
      
      antlr::RefAST ast = antlr::nullAST;

      pp->program();

      ast = pp->getAST();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::STAR, (int)ast->getType());
      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::MOD, (int)child->getType());

      antlr::RefAST grand = child->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)grand->getType());
      grand = grand->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)grand->getType());      

      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)child->getType());
      
    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testApply(){
    try{
      *ss << "foo(); foo(12);";
      
      antlr::RefAST ast = antlr::nullAST;
      
      pp->program();

      ast = pp->getAST();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::APPLY, (int)ast->getType());
      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::NIL, (int)child->getType());

      ast = ast->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::APPLY, (int)ast->getType());
      child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)child->getType());

    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }


  void testBitwise(){
    try{
      *ss << "12&5|6^34&2";
      
      antlr::RefAST ast = antlr::nullAST;
      
      pp->program();

      ast = pp->getAST();

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::BITXOR, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::BITOR, (int)child->getType());
      antlr::RefAST grandchild = child->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::BITAND, (int)grandchild->getType());
      grandchild = grandchild->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)grandchild->getType());

      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::BITAND, (int)child->getType());
      grandchild = child->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)grandchild->getType());
      grandchild = grandchild->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)grandchild->getType());

    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }


  void testSum(){
    try{
      *ss << "a*10+b*14-23";
      
      antlr::RefAST ast = antlr::nullAST;
      
      pp->program();

      ast = pp->getAST();

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::MINUS, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::PLUS, (int)child->getType());
      antlr::RefAST grandchild = child->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::STAR, (int)grandchild->getType());
      antlr::RefAST great = grandchild->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)great->getType());
      great = great->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)great->getType());
      grandchild = grandchild->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::STAR, (int)grandchild->getType());
      great = grandchild->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)great->getType());
      great = great->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)great->getType());

      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)child->getType());


    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }


  void testCompareSimple(){
    try{
      *ss << "a == b;";
      
      antlr::RefAST ast = antlr::nullAST;
      
      pp->program();
      ast = pp->getAST();

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::EQUAL, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());


    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testCompareSimple2(){
    try{
      *ss << "a is b;";
      
      antlr::RefAST ast = antlr::nullAST;
      
      pp->program();
      ast = pp->getAST();

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::IS, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());


    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testCompareComplex1(){
    try{
      *ss << "a is not b;";
      
      antlr::RefAST ast = antlr::nullAST;
      
      pp->program();
      ast = pp->getAST();

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::NIS, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());


    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }


  void testCompareComplex2(){
    try{
      *ss << "a not identically b;";
      
      antlr::RefAST ast = antlr::nullAST;

      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::NIDENTICALLY, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());


    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testCompareComplex3(){
    try{
      *ss << "a is not <= b;";
      
      antlr::RefAST ast = antlr::nullAST;

      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::GREA, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());


    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testNot1(){
    try{
      *ss << "not a;";
      
      antlr::RefAST ast = antlr::nullAST;

      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::NOT, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());


    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }


  void testNot2(){
    try{
      *ss << "not a == b;";
      
      antlr::RefAST ast = antlr::nullAST;

      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::NOT, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::EQUAL, (int)child->getType());
      antlr::RefAST grand = child->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)grand->getType());
      grand = grand->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)grand->getType());

    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }


  void testBoolean1(){
    try{
      *ss << "a and 4 and 4.5;";
      
      antlr::RefAST ast = antlr::nullAST;

      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::KW_and, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::KW_and, (int)child->getType());
      antlr::RefAST grand = child->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)grand->getType());
      grand = grand->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::FLOAT, (int)grand->getType());

    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }


  void testBoolean2(){
    try{
      *ss << "a and 4 or 4.5;";
      
      antlr::RefAST ast = antlr::nullAST;

      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::KW_or, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::KW_and, (int)child->getType());

      antlr::RefAST grand = child->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)grand->getType());
      grand = grand->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)grand->getType());

      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::FLOAT, (int)child->getType());


    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }
  void testTuple1(){
    try{
      *ss << "a, ;";
      
      antlr::RefAST ast = antlr::nullAST;

      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::TUPLE, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());


    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testTuple2(){
    try{
      *ss << "a, 1;";
      
      antlr::RefAST ast = antlr::nullAST;

      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::TUPLE, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)child->getType());


    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testTuple3(){
    try{
      *ss << "a, 1, 1.1;";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::TUPLE, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::FLOAT, (int)child->getType());


    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testTuple4(){
    try{
      *ss << "a, 1, 1.1, ,;";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);

      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::TUPLE, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::FLOAT, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::NIL, (int)child->getType());

      CPPUNIT_ASSERT_EQUAL(4, (int)ast->getNumberOfChildren());

    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }


  void testAssign1(){
    try{
      *ss << "a = 5";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());
      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ASSIGN, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)child->getType());



    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testLambda1(){
    try{

      *ss << "{x = 4; foo(x); x.bar()}";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());
      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::LAMBDA, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::PARAMS, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(0, (int)child->getNumberOfChildren());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::BODY, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(3, (int)child->getNumberOfChildren());



    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testLambda2(){
    try{

      *ss << "as {x = 4; foo(x); x.bar()}";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());
      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::LAMBDA, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::PARAMS, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(0, (int)child->getNumberOfChildren());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::BODY, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(3, (int)child->getNumberOfChildren());



    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testLambda3(){
    try{

      *ss << "as () {x = 4; foo(x); x.bar()}";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());
      //cout << ast->toStringTree() << endl;

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::LAMBDA, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::PARAMS, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(0, (int)child->getNumberOfChildren());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::BODY, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(3, (int)child->getNumberOfChildren());



    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }
  void testLambda4(){
    try{

      *ss << "as x {x = 4; foo(x); x.bar()}";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);
      //cout << ast->toStringTree() << endl;
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());


      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::LAMBDA, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::PARAMS, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(1, (int)child->getNumberOfChildren());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::BODY, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(3, (int)child->getNumberOfChildren());



    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testLambda5(){
    try{
      *ss << "as x, y {x = 4; foo(x); y.bar()}";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);
      //cout << ast->toStringTree() << endl;
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::LAMBDA, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::PARAMS, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(2, (int)child->getNumberOfChildren());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::BODY, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(3, (int)child->getNumberOfChildren());



    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testLambda6(){
    try{

      *ss << "as (x, y) {x = 4; foo(x); y.bar()}";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);
      //cout << ast->toStringTree() << endl;
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::LAMBDA, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::PARAMS, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(2, (int)child->getNumberOfChildren());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::BODY, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(3, (int)child->getNumberOfChildren());



    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }


  void testLambda7(){
    try{

      *ss << "as (x) {x = 4; foo(x); y.bar()}";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);
      //cout << ast->toStringTree() << endl;
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::LAMBDA, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::PARAMS, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(1, (int)child->getNumberOfChildren());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::BODY, (int)child->getType());
      CPPUNIT_ASSERT_EQUAL(3, (int)child->getNumberOfChildren());



    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testDefine1(){
    try{

      *ss << "def x 3";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);
      //cout << ast->toStringTree() << endl;
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::KW_def, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::INT, (int)child->getType());

    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testMacro1(){
    try{

      *ss <<"install for stuff;"<<endl
          <<"for 1, 2, 3 as x {print(x)};";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);
      //cout << ast->toStringTree() << endl;
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::KW_install, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());

      ast = ast->getNextSibling();
      CPPUNIT_ASSERT(ast != antlr::nullAST);
      //cout << ast->toStringTree() << endl;
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::MACRO, (int)ast->getType());
      child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::TUPLE, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::LAMBDA, (int)child->getType());
      

    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }

  void testMacro2(){
    try{

      *ss <<"install for stuff;"<<endl
          <<"for f(y) as x {print(x)};";
      
      antlr::RefAST ast = antlr::nullAST;
      pp->program();
      ast = pp->getAST();

      CPPUNIT_ASSERT(ast != antlr::nullAST);
      //cout << ast->toStringTree() << endl;
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::KW_install, (int)ast->getType());

      antlr::RefAST child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::ID, (int)child->getType());

      ast = ast->getNextSibling();
      CPPUNIT_ASSERT(ast != antlr::nullAST);
      //cout << ast->toStringTree() << endl;
      CPPUNIT_ASSERT_EQUAL(2, (int)ast->getNumberOfChildren());

      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::MACRO, (int)ast->getType());
      child = ast->getFirstChild();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::APPLY, (int)child->getType());
      child = child->getNextSibling();
      CPPUNIT_ASSERT_EQUAL((int)PlantainParserTokenTypes::LAMBDA, (int)child->getType());
      

    }catch(antlr::RecognitionException ex){
      CPPUNIT_FAIL(ex.getFileLineColumnString());
    }catch(antlr::ANTLRException ex){
      CPPUNIT_FAIL(ex.toString());
    }

  }
  



public:

  static CppUnit::Test* suite(){
    CppUnit::TestSuite *suite = new CppUnit::TestSuite("SimpleParserTest");
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testSimple", 
                                                              &SimpleParserTest::testSimple));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testLookup", 
                                                              &SimpleParserTest::testLookup));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testLookup2", 
                                                              &SimpleParserTest::testLookup2));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testApply", 
                                                              &SimpleParserTest::testApply));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testProduct", 
                                                              &SimpleParserTest::testProduct));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testProduct2", 
                                                              &SimpleParserTest::testProduct2));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testBitwise", 
                                                              &SimpleParserTest::testBitwise));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testSum", 
                                                              &SimpleParserTest::testSum));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testCompareSimple", 
                                                              &SimpleParserTest::testCompareSimple));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testCompareSimple2", 
                                                              &SimpleParserTest::testCompareSimple2));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testCompareComplex1", 
                                                              &SimpleParserTest::testCompareComplex1));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testCompareComplex2", 
                                                              &SimpleParserTest::testCompareComplex2));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testCompareComplex3", 
                                                              &SimpleParserTest::testCompareComplex3));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testNot1", 
                                                              &SimpleParserTest::testNot1));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testNot2", 
                                                              &SimpleParserTest::testNot2));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testBoolean1", 
                                                              &SimpleParserTest::testBoolean1));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testBoolean2", 
                                                              &SimpleParserTest::testBoolean2));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testTuple1", 
                                                              &SimpleParserTest::testTuple1));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testTuple2", 
                                                              &SimpleParserTest::testTuple2));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testTuple3", 
                                                              &SimpleParserTest::testTuple3));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testTuple4", 
                                                              &SimpleParserTest::testTuple3));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testAssign1", 
                                                              &SimpleParserTest::testAssign1));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testLambda1", 
                                                              &SimpleParserTest::testLambda1));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testLambda2", 
                                                              &SimpleParserTest::testLambda2));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testLambda3", 
                                                              &SimpleParserTest::testLambda3));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testLambda4", 
                                                              &SimpleParserTest::testLambda4));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testLambda5", 
                                                              &SimpleParserTest::testLambda5));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testLambda6", 
                                                              &SimpleParserTest::testLambda6));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testLambda7", 
                                                              &SimpleParserTest::testLambda7));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testDefine1", 
                                                              &SimpleParserTest::testDefine1));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testMacro1", 
                                                              &SimpleParserTest::testMacro1));
    suite->addTest( new CppUnit::TestCaller<SimpleParserTest>("testMacro2", 
                                                              &SimpleParserTest::testMacro2));
    return suite;
  }
};
